Skip to main content

media_pp\elements\driver\webrtc/
command.rs

1use crossbeam_channel::Sender;
2use str0m::{
3    RtcError,
4    change::{SdpAnswer, SdpOffer},
5    format::Codec,
6    media::{Direction, MediaKind, Mid},
7};
8use thiserror::Error as ThisError;
9
10use crate::buffer::MediaBuffer;
11
12/// Identifies one outbound track before/after negotiation. str0m's own
13/// [`Mid`] doesn't exist until the SDP exchange that creates it completes,
14/// so this is a stable handle usable from the moment
15/// [`super::track::WebRtcHandle::add_track`] returns.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct TrackId(pub(super) u64);
18
19/// Errors specific to `WebRtcPeer`/`WebRtcHandle`/`WebRtcTrackSink`.
20/// Converts into the crate-wide `Error` via `?` (see [`crate::error::Error`]).
21#[derive(Debug, ThisError)]
22pub enum WebRtcError {
23    #[error("str0m error: {0}")]
24    Str0m(#[from] RtcError),
25
26    #[error("network error: {0}")]
27    Io(#[from] std::io::Error),
28
29    #[error(
30        "WebRtcTrackSink only accepts already-encoded Packet buffers \
31         (an encoder's output), got a {0}"
32    )]
33    UnsupportedBuffer(&'static str),
34
35    #[error("WebRTC packet has no PTS")]
36    MissingPacketPts,
37
38    #[error("WebRTC packet has a negative PTS: {0}")]
39    NegativePacketPts(i64),
40
41    #[error("WebRTC packet has an invalid time base: {numerator}/{denominator}")]
42    InvalidPacketTimeBase { numerator: i32, denominator: i32 },
43
44    #[error(
45        "WebRTC packet timestamp overflows MediaTime: pts={pts}, time_base={numerator}/{denominator}"
46    )]
47    PacketTimestampOverflow {
48        pts: u64,
49        numerator: i32,
50        denominator: i32,
51    },
52
53    #[error("WebRtcPeer's run() has already ended")]
54    Closed,
55}
56
57/// One command sent from a [`WebRtcHandle`]/[`WebRtcTrackSink`] (any
58/// thread) into [`super::peer::WebRtcPeer::run`]'s own thread.
59pub(super) enum Command {
60    AddTrack(TrackId, MediaKind, Direction, Codec),
61    Push(TrackId, MediaBuffer),
62    SetAnswer(SdpAnswer),
63    /// A fresh offer from the *remote* peer (their own renegotiation, e.g.
64    /// them adding a track) — out of scope to originate ourselves in v1
65    /// (see the module docs), but still something this side has to be able
66    /// to *accept*, or a two-way call could only ever renegotiate from one
67    /// side. `Sender` here is a one-shot rendezvous, same idea as
68    /// [`crate::control::ControlSender::send`]'s ack channel.
69    AcceptOffer(
70        SdpOffer,
71        Sender<std::result::Result<SdpAnswer, WebRtcError>>,
72    ),
73}
74
75/// Where one outbound track is in str0m's own offer/answer dance — mirrors
76/// str0m's own `chat.rs` example's `TrackOutState`.
77pub(super) enum TrackOutState {
78    ToOpen(MediaKind, Direction),
79    Negotiating(Mid),
80    Open(Mid),
81}
82
83impl TrackOutState {
84    pub(super) fn mid(&self) -> Option<Mid> {
85        match self {
86            TrackOutState::ToOpen(..) => None,
87            TrackOutState::Negotiating(mid) | TrackOutState::Open(mid) => Some(*mid),
88        }
89    }
90}